package com.pactera.asmp.server.service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.pactera.asmp.server.common.constants.Constants;
import com.pactera.asmp.server.common.constants.ResultCode;
import com.pactera.asmp.server.common.exception.CustomException;
import com.pactera.asmp.server.dao.DeviceInfoMapper;
import com.pactera.asmp.server.dao.MasterComputerMapper;
import com.pactera.asmp.server.dao.TProjectMasterComputerDbcMapper;
import com.pactera.asmp.server.entity.ProjectMastercBindDto;
import com.pactera.asmp.server.entity.ProjectMastercDbcBindDto;
import com.pactera.asmp.server.entity.ResponseResult;
import com.pactera.asmp.server.pojo.DeviceInfo;
import com.pactera.asmp.server.pojo.MasterComputer;
import com.pactera.asmp.server.pojo.MastercProjectDbcVo;
import com.pactera.asmp.server.pojo.ProjectDbcInfo;
import com.pactera.asmp.server.pojo.ProjectMasterComputerDbc;
import com.pactera.asmp.server.pojo.TProjectMasterComputerDbc;
import com.pactera.asmp.server.pojo.TProjectMasterComputerDbcExample;
import com.pactera.asmp.server.pojo.User;
import com.pactera.asmp.server.utils.AssertUtil;

@Service
public class ProjectMastercDbcServiceImpl implements IProjectMastercDbcService {

    @Autowired
    private TProjectMasterComputerDbcMapper projectMasterComputerDbcMapper;

    @Autowired
    private DeviceInfoMapper deviceInfoMapper;

    @Autowired
    private MasterComputerMapper masterComputerMapper;

    @Override
    public int insert(List<TProjectMasterComputerDbc> projectMastercDbcs) {
        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if (null == currUser) {
            throw new CustomException(ResultCode.PERMISSION_EXPIRE);
        }
        for (TProjectMasterComputerDbc projectMastercDbc : projectMastercDbcs) {
            // 验证参数
            this.checkParam(projectMastercDbc);

            projectMastercDbc.setCreateUserId(currUser.getId());
            projectMastercDbc.setUpdateUserId(currUser.getId());
            projectMastercDbc.setCreateTime(LocalDateTime.now());
            projectMastercDbc.setUpdateTime(LocalDateTime.now());
        }
        return projectMasterComputerDbcMapper.batchInsert(projectMastercDbcs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDbc(ProjectMastercDbcBindDto projectMastercDbcBindDto) {
        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if (null == currUser) {
            throw new CustomException(ResultCode.PERMISSION_EXPIRE);
        }
        int count = 0;
        Integer projectId = projectMastercDbcBindDto.getProjectId();
        List<TProjectMasterComputerDbc> projectMastercDbcs = projectMastercDbcBindDto.getList();
        for (TProjectMasterComputerDbc projectMastercDbc : projectMastercDbcs) {
            if (null == projectMastercDbc.getDbcId() || 0 == projectMastercDbc.getDbcId()) {
                throw new CustomException(ResultCode.PARAM_IS_BLANK);
            }
            projectMastercDbc.setProjectId(projectId);
            this.checkParam(projectMastercDbc);
            projectMastercDbc.setUpdateUserId(currUser.getId());
            projectMastercDbc.setUpdateTime(LocalDateTime.now());

            count += projectMasterComputerDbcMapper.updateByPrimaryKeySelective(projectMastercDbc);
        }
        return count;
    }

    @Override
    public int batchDelete(List<TProjectMasterComputerDbc> projectMastercDbcs) {
        TProjectMasterComputerDbcExample example = new TProjectMasterComputerDbcExample();
        for (TProjectMasterComputerDbc projectMastercDbc : projectMastercDbcs) {
            this.checkParam(projectMastercDbc);
            example.or()
                    .andProjectIdEqualTo(projectMastercDbc.getProjectId())
                    .andMasterComputerIdEqualTo(projectMastercDbc.getMasterComputerId());
        }
        return projectMasterComputerDbcMapper.deleteByExample(example);
    }

    @Override
    public List<TProjectMasterComputerDbc> selective(Integer projectId, Integer masterComputerId) {
        TProjectMasterComputerDbcExample example = new TProjectMasterComputerDbcExample();
        TProjectMasterComputerDbcExample.Criteria criteria = example.createCriteria();

        if (null != projectId && 0 != projectId) {
            criteria.andProjectIdEqualTo(projectId);
        }
        if (null != masterComputerId && 0 != masterComputerId) {
            criteria.andMasterComputerIdEqualTo(masterComputerId);
        }
        return projectMasterComputerDbcMapper.selectByExample(example);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchBind(ProjectMastercBindDto projectMastercBindDto) {
        List<TProjectMasterComputerDbc> projectMastercDbcs = this.selective(projectMastercBindDto.getProjectId(), null);
        List<Integer> masterIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(projectMastercDbcs)) {
            masterIdList = projectMastercDbcs.stream().map(TProjectMasterComputerDbc::getMasterComputerId).distinct().collect(Collectors.toList());
        }

        List<TProjectMasterComputerDbc> newProjectMastercDbcs = new ArrayList<>();
        if (!CollectionUtils.isEmpty(projectMastercBindDto.getMasterComputerIds())) {
            for (Integer masterId : projectMastercBindDto.getMasterComputerIds()) {
                if (!masterIdList.contains(masterId)) {
                    TProjectMasterComputerDbc projectMasterComputerDbc = new TProjectMasterComputerDbc();
                    projectMasterComputerDbc.setProjectId(projectMastercBindDto.getProjectId());
                    projectMasterComputerDbc.setMasterComputerId(masterId);
                    newProjectMastercDbcs.add(projectMasterComputerDbc);
                } else {
                    masterIdList.remove(masterId);
                }
            }
        }

        // 批量删除
        if (!CollectionUtils.isEmpty(masterIdList)) {
            // 检测解绑的设备是否正在执行任务
            List<DeviceInfo> deviceInfos = deviceInfoMapper.selectByMasterComputerIds(masterIdList, 1);
            if (!CollectionUtils.isEmpty(deviceInfos)) {
                throw new CustomException(ResultCode.BUSINESS_PROJECT_DEVICE_UNBIND_FAIL);
            }

            TProjectMasterComputerDbcExample example = new TProjectMasterComputerDbcExample();
            example.createCriteria().andProjectIdEqualTo(projectMastercBindDto.getProjectId())
                    .andMasterComputerIdIn(masterIdList);
            projectMasterComputerDbcMapper.deleteByExample(example);
        }

        // 批量添加
        if (!CollectionUtils.isEmpty(newProjectMastercDbcs)) {
            this.insert(newProjectMastercDbcs);
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult mastercBind(MastercProjectDbcVo mastercProjectDbcVo) {
        AssertUtil.notNull(mastercProjectDbcVo, "参数异常");
        AssertUtil.notNull(mastercProjectDbcVo.getMasterComputerId(), "上位机ID不允许为空");

        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if (currUser == null) throw new CustomException(ResultCode.PERMISSION_EXPIRE);
        LocalDateTime now = LocalDateTime.now();

        // 1. 修改昵称
        if(!StringUtils.isEmpty(mastercProjectDbcVo.getNickName())) {
            AssertUtil.isTrue(mastercProjectDbcVo.getNickName().matches(Constants.REGEXP_FIRST_LAST_NOT_SPACE),"昵称格式不正确");
            MasterComputer masterComputer = new MasterComputer();
            masterComputer.setId(mastercProjectDbcVo.getMasterComputerId());
            masterComputer.setNickName(mastercProjectDbcVo.getNickName());
            int count = masterComputerMapper.updateNickName(masterComputer);
            if (count < 1) throw new CustomException(ResultCode.DATA_IS_WRONG);
        }
        // 2. 读取当前设备的绑定关系
        List<TProjectMasterComputerDbc> list = this.selective(null, mastercProjectDbcVo.getMasterComputerId());

        // 3. 配置增、删、改的关系
        if (!CollectionUtils.isEmpty(list) && CollectionUtils.isEmpty(mastercProjectDbcVo.getProjectDbcInfos())) {
            // db有数据，参数无数据，表示删除清空
            TProjectMasterComputerDbcExample example = new TProjectMasterComputerDbcExample();
            example.createCriteria().andMasterComputerIdEqualTo(mastercProjectDbcVo.getMasterComputerId());
            int count = projectMasterComputerDbcMapper.deleteByExample(example);
            if (count < 1) throw new CustomException(ResultCode.DATA_IS_WRONG);
            // TODO 删除台架大屏缓存数据
        }
        else if (CollectionUtils.isEmpty(list) && !CollectionUtils.isEmpty(mastercProjectDbcVo.getProjectDbcInfos())) {
            // db无数据，参数有数据，表示全部新增
            List<TProjectMasterComputerDbc> insertList = new ArrayList<>();
            for(ProjectDbcInfo projectDbcInfo :mastercProjectDbcVo.getProjectDbcInfos()){
                TProjectMasterComputerDbc projectMasterComputerDbc = new TProjectMasterComputerDbc();
                insertList.add(projectMasterComputerDbc);
                projectMasterComputerDbc.setUpdateTime(now);
                projectMasterComputerDbc.setUpdateUserId(currUser.getId());
                projectMasterComputerDbc.setCreateTime(now);
                projectMasterComputerDbc.setCreateUserId(currUser.getId());
                projectMasterComputerDbc.setProjectId(projectDbcInfo.getProjectId());
                projectMasterComputerDbc.setMasterComputerId(mastercProjectDbcVo.getMasterComputerId());
                projectMasterComputerDbc.setDbcId(projectDbcInfo.getDbcId());
            }
            if(!CollectionUtils.isEmpty(insertList)){
                int count = projectMasterComputerDbcMapper.batchInsert(insertList);
                if (count < 1) throw new CustomException(ResultCode.DATA_IS_WRONG);
            }
        }
        else if (!CollectionUtils.isEmpty(list) && !CollectionUtils.isEmpty(mastercProjectDbcVo.getProjectDbcInfos())) {

            // 删除
            list.stream().filter(dbItem -> {
                return !mastercProjectDbcVo.getProjectDbcInfos().stream()
                        .noneMatch(paramItem -> dbItem.getProjectId().equals(paramItem.getProjectId())
                                && dbItem.getMasterComputerId().equals(mastercProjectDbcVo.getMasterComputerId()));
            }).forEach(dbItem -> {
                TProjectMasterComputerDbcExample example = new TProjectMasterComputerDbcExample();
                example.createCriteria().andProjectIdEqualTo(dbItem.getProjectId())
                        .andMasterComputerIdEqualTo(dbItem.getMasterComputerId());
                int count = projectMasterComputerDbcMapper.deleteByExample(example);
                if (count < 1)
                    throw new CustomException(ResultCode.DATA_IS_WRONG);
            });

            // 修改
            mastercProjectDbcVo.getProjectDbcInfos().stream().filter(paramItem -> {
                return list.stream()
                        .anyMatch(dbItem -> dbItem.getProjectId().equals(paramItem.getProjectId())
                                && dbItem.getMasterComputerId().equals(mastercProjectDbcVo.getMasterComputerId())
                                && !Objects.equals(dbItem.getDbcId(), paramItem.getDbcId()));
            }).forEach(paramItem -> {
                TProjectMasterComputerDbc updatPo = new TProjectMasterComputerDbc();
                updatPo.setProjectId(paramItem.getProjectId());
                updatPo.setMasterComputerId(mastercProjectDbcVo.getMasterComputerId());
                updatPo.setDbcId(paramItem.getDbcId());
                updatPo.setUpdateUserId(currUser.getId());
                updatPo.setUpdateTime(now);
                int count = this.projectMasterComputerDbcMapper.updateByPrimaryKeySelective(updatPo);
                if (count < 1)
                    throw new CustomException(ResultCode.DATA_IS_WRONG);
            });

            // 新增
            List<TProjectMasterComputerDbc> insertList = mastercProjectDbcVo.getProjectDbcInfos().stream()
                    .filter(paramItem -> {
                        return list.stream().noneMatch(dbItem -> dbItem.getProjectId().equals(paramItem.getProjectId())
                                && dbItem.getMasterComputerId().equals(mastercProjectDbcVo.getMasterComputerId()));
                    }).map(paramItem -> {
                        TProjectMasterComputerDbc newPo = new TProjectMasterComputerDbc();
                        newPo.setProjectId(paramItem.getProjectId());
                        newPo.setMasterComputerId(mastercProjectDbcVo.getMasterComputerId());
                        newPo.setDbcId(paramItem.getDbcId());
                        newPo.setCreateUserId(currUser.getId());
                        newPo.setCreateTime(now);
                        newPo.setUpdateUserId(currUser.getId());
                        newPo.setUpdateTime(now);
                        return newPo;
                    }).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(insertList)) {
                int count = this.insert(insertList);
                if (count < 1)
                    throw new CustomException(ResultCode.DATA_IS_WRONG);
            }
        }
        return ResponseResult.defaultSuccess(1);
    }

    @Override
    public List<ProjectMasterComputerDbc> getProjectMastercDbcsByMastercId(Integer masterComputerId) {
        AssertUtil.notNull(masterComputerId,"上位机ID不允许为空");
        return projectMasterComputerDbcMapper.getProjectMastercDbcsByMastercId(masterComputerId);
    }

    /**
     * 验证必传参数
     *
     * @param projectMastercDbc
     */
    private void checkParam(TProjectMasterComputerDbc projectMastercDbc) {
        Integer projectId = projectMastercDbc.getProjectId();
        Integer masterComputerId = projectMastercDbc.getMasterComputerId();
        if (null == projectId || 0 == projectId
                || null == masterComputerId || 0 == masterComputerId) {
            throw new CustomException(ResultCode.PARAM_IS_BLANK);
        }
    }

}
